
import decimal
import hashlib

import time
import random

from application import db
from common.libs import Helper
from common.libs.Restful import Restful
from common.models.foods.Food import Food
from common.models.foods.FoodSaleChangeLog import FoodSaleChangeLog
from common.models.order.PayOrder import PayOrder
from common.models.order.PayOrderCallback import PayOrderCallbackDatum
from common.models.order.PayOrderItem import PayOrderItem
from common.libs.FoodService.FoodService import FoodService

class PayService(object):

    def __init__(self):
        pass

    def createOrder(self, member_id, items=None, params=None):
        '''
        :param member_id: 用户id
        :param items: 多个下单商品的列表
        :param params: 其他参数
        :return: 构造下单数据生成Response对象并返回
        '''
        pay_price = decimal.Decimal(0.00)
        continue_cnt = 0
        food_ids = []
        # 根据订单商品列表，计算订单总价
        for item in items:
            if decimal.Decimal(item['price']) < 0:
                continue_cnt += 1
                continue
            pay_price = pay_price + decimal.Decimal(item['price'])*int(item['number'])
            food_ids.append(item['id'])

        if continue_cnt >= len(items):
            return Restful.format_error(msg='选择商品为空')

        yun_price = decimal.Decimal(params['yun_price'] if params and 'yun_price' in params else 0)
        note = params['note'] if params and 'note' in params else ''
        total_price = decimal.Decimal(pay_price) + yun_price

        # 并发处理 使用数据库事务的互斥锁with_for_update，一个用户在执行下单操作的过程中，别的用户只能等待，当一个用户完成后，此用户才能响应操作
        try:
            tmp_food_list = db.session.query(Food).filter(Food.id.in_(food_ids)).with_for_update().all()

            # 用字典将一个列表的id和某些字段关联起来，方便在其他地方查找
            tmp_food_stock_mapping = {}
            for tmp_item in tmp_food_list:
                tmp_food_stock_mapping[tmp_item.id] = tmp_item.stock

            # 生成Order模型并赋值
            model_pay_order = PayOrder()
            # 订单的唯一标识，在和支付宝对接的时候会用到此字段，使用当前时间+随机数一起md5得到
            model_pay_order.order_sn = self.geneOrderSn()
            model_pay_order.member_id = member_id
            model_pay_order.total_price = total_price
            model_pay_order.yun_price = yun_price
            model_pay_order.pay_price = pay_price
            model_pay_order.note = note
            # 设置订单的初始状态
            model_pay_order.status = -8
            model_pay_order.express_status = -8
            model_pay_order.updated_time = Helper.geneDatetime()
            model_pay_order.created_time = Helper.geneDatetime()
            # 先add，但是不进行commit操作，等待所有操作都通过后在进行提交
            db.session.add(model_pay_order)

            # 生成OrderItem为一个订单里面的每个商品都生成一条记录
            for item in items:
                tmp_left_stock = tmp_food_stock_mapping[item['id']]
                if decimal.Decimal(item['price']) < 0:
                    continue
                if int(item['number']>int(tmp_left_stock)):
                    raise Exception('您购买的美食太火爆了，剩余：%s，您购买：%s'% (tmp_left_stock, item['number']))


                tmp_ret = db.session.query(Food).filter_by(id=item['id']).update({
                    'stock': int(tmp_left_stock) - int(item['number'])
                })

                if not tmp_ret:
                    raise Exception("下单失败，请重新下单")

                tmp_pay_item = PayOrderItem()
                tmp_pay_item.pay_order_id = model_pay_order.id
                tmp_pay_item.member_id = member_id
                tmp_pay_item.quantity = item['number']
                tmp_pay_item.price = item['price']
                tmp_pay_item.food_id = item['id']
                tmp_pay_item.note = note
                tmp_pay_item.updated_time = tmp_pay_item.created_time = Helper.geneDatetime()

                db.session.add(tmp_pay_item)

                FoodService.setStockChange(item['id'], -item['number'], "在线购买")

            db.session.commit()

            resp = {
                'id': model_pay_order.id,
                'order_sn': model_pay_order.order_sn,
                'total_price': str(model_pay_order.total_price)
            }
            return Restful.success(msg='下单成功', data=resp)
        except Exception as e:
            db.session.rollback()
            print(e)
            return Restful.format_error(msg='下单失败', code=1000)

    def orderSuccess(self, pay_order_id=0, params=None):
        try:
            pay_order_info = PayOrder.query.filter_by(id=pay_order_id).first()
            # 如果支付订单中的状态已经是等待的时候了，就不用改状态了
            if not pay_order_info or pay_order_info.status not in [-8, -7]:
                return True

            # 修改订单状态
            pay_order_info.pay_sn = params['pay_sn'] if params and 'pay_sn' in params else ''
            pay_order_info.status = 1 #改为已支付
            pay_order_info.express_status = -7 #改为待确认
            pay_order_info.pay_time = Helper.geneDatetime()
            pay_order_info.update_time = Helper.geneDatetime()
            db.session.add(pay_order_info)

            # 记录售卖信息
            pay_order_items = PayOrderItem.query.filter_by(pay_order_id=pay_order_id).all()
            for order_item in pay_order_items:
                tmp_model_sale_log = FoodSaleChangeLog()
                tmp_model_sale_log.food_id = order_item.food_id
                tmp_model_sale_log.quantity = order_item.quantity
                tmp_model_sale_log.price = order_item.price
                tmp_model_sale_log.member_id = order_item.member_id
                tmp_model_sale_log.created_time = Helper.geneDatetime()
                db.session.add(tmp_model_sale_log)

            db.session.commit()
        except Exception as e:
            db.session.rollback()

    def addPayCallbackData(self, pay_order_id=0, type='pay', data=''):
        model_callback = PayOrderCallbackDatum()
        model_callback.pay_order_id = pay_order_id
        if type == 'pay':
            model_callback.pay_data = data
            model_callback.refund_data = ''
        else:
            model_callback.pay_data = ''
            model_callback.refund_data = data

        model_callback.created_time = model_callback.updated_time = Helper.geneDatetime()

        db.session.add(model_callback)
        db.session.commit()

    def geneOrderSn(self):
        m = hashlib.md5()
        sn = None
        while True:
            str = "%s-%s"%(int(round(time.time()*1000)), random.randint(0, 99999999))
            m.update(str.encode('utf-8'))
            sn = m.hexdigest()
            if not PayOrder.query.filter_by(order_sn=sn).first():
                break
        return sn
